UNPKG

@khoohaoyit/image-size

Version:

A stream based image size extractor in Node

160 lines (159 loc) 9.39 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractHeifSize = exports.extractHeicSize = exports.extractAvifSize = void 0; const extractSize = (formats, targetFormat) => { return function (stream) { return __asyncGenerator(this, arguments, function* () { const ftypBox = yield __await(readFtypBox(stream, 0)); if (ftypBox.type !== 'ftyp') return yield __await(void 0); for (const currentFormat of formats) { const foundIndex = [ftypBox.minorVersion, ...ftypBox.compatibleBrands].indexOf(currentFormat); if (foundIndex === -1) continue; if (currentFormat !== targetFormat) return yield __await(void 0); break; } loop: for (let currentBox; currentBox = yield __await(readBox(stream, currentBox ? currentBox.offset + currentBox.size : ftypBox.offset + ftypBox.size));) switch (currentBox.type) { default: break; case 'mdat': return yield __await(void 0); case 'meta': { const parentBox = currentBox; for (let currentBox; isParentLastChildBox(parentBox, currentBox) && (currentBox = yield __await(readBox(stream, currentBox ? currentBox.offset + currentBox.size : parentBox.itemOffset + 4)));) switch (currentBox.type) { default: break; case 'iprp': { const parentBox = currentBox; const ipcoBox = yield __await(readBox(stream, parentBox.itemOffset)); if (ipcoBox.type !== 'ipco') throw new Error(`boxType isn't ipco`); for (let currentBox; isParentLastChildBox(parentBox, currentBox) && (currentBox = yield __await(readBox(stream, currentBox ? currentBox.offset + currentBox.size : ipcoBox.itemOffset)));) switch (currentBox.type) { default: break; case 'ispe': { const width = yield __await(stream.readUint32BE(currentBox.itemOffset + 4)); const height = yield __await(stream.readUint32BE(currentBox.itemOffset + 4 + 4)); return yield __await(yield yield __await({ width, height })); } break; } } break; // case 'iloc': // break; // case 'iinf': { // const parentBox = currentBox; // const itemCount = await stream.readUint16BE(parentBox.itemOffset); // for ( // let currentBox, remain = itemCount // ; currentBox = await readFullBox( // stream, // currentBox // ? currentBox.offset + currentBox.size // : parentBox.itemOffset + 2 // ), remain // ; --remain // ) switch (currentBox.type) { // default: // break; // case 'infe': { // const itemId = await stream.readUint16BE(currentBox.itemOffset); // // const itemName = await stream.readString(); // console.log(itemId); // } break; // } // } break; } break loop; } break; } }); }; }; exports.extractAvifSize = extractSize(['avif', 'heic', 'heif'], 'avif'); exports.extractHeicSize = extractSize(['avif', 'heic', 'heif'], 'heic'); exports.extractHeifSize = extractSize(['avif', 'heic', 'heif'], 'heif'); function readFtypBox(stream, offset) { return __awaiter(this, void 0, void 0, function* () { const box = yield readBox(stream, offset); if (box.type !== 'ftyp') throw new Error(`Expected ftyp box type, received: ${box.type}`); const majorBrand = yield stream.readString(box.itemOffset, 4); const minorVersion = yield stream.readUint32BE(box.itemOffset + 4); const compatibleBrands = yield stream.readString(box.itemOffset + 8, box.offset + box.size - (box.itemOffset + 8)) .then(text => { var _a; return (_a = text.match(/..../g)) !== null && _a !== void 0 ? _a : []; }); return Object.assign(Object.assign({}, box), { majorBrand, minorVersion, compatibleBrands }); }); } function readBox(stream, offset) { return __awaiter(this, void 0, void 0, function* () { const size = yield stream.readUint32BE(offset); const typeBuffer = yield stream.read(offset + 4, 4); if ( // http://www.columbia.edu/kermit/ascii.html typeBuffer[0] < 32 || typeBuffer[0] > 126 || typeBuffer[1] < 32 || typeBuffer[1] > 126 || typeBuffer[2] < 32 || typeBuffer[2] > 126 || typeBuffer[3] < 32 || typeBuffer[3] > 126) throw new Error(`type isn't a printable characters`); return { size: size, type: typeBuffer.toString(), offset: offset, itemOffset: offset + 8, }; }); } function readFullBox(stream, offset) { return __awaiter(this, void 0, void 0, function* () { const box = yield readBox(stream, offset); const version = yield stream.readUint8(box.itemOffset); const flags = yield stream.readUintBE(box.itemOffset + 1, 3); return Object.assign(Object.assign({}, box), { version, flags, itemOffset: box.itemOffset + 4 }); }); } function isParentLastChildBox(parentBox, currentBox) { if (!currentBox) return true; return currentBox.offset + currentBox.size < parentBox.offset + parentBox.size; }